package com.symone.crawler.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.symone.crawler.App;
import com.symone.crawler.action.Catcher;
import com.symone.crawler.config.AirBnbConfig;
import com.symone.crawler.config.CrawlerConfig;
import com.symone.crawler.data.ProxyData;
import com.symone.crawler.log.Log;
import com.symone.crawler.log.LogFactory;
import com.symone.crawler.util.DBUtil;
import com.symone.crawler.util.DateTimeUtil;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class BookingService {

    private static Log logger = LogFactory.getLog(BookingService.class);
    private static int total = 0;
    private static int success = 0;
    private static int failed = 0;

    private volatile Catcher catcher = new Catcher();

    private ProxyData proxy;
    private Entity room;
    private Map<String,String> params;

    public BookingService(Entity room,Map<String,String> params){
        super();
        this.room = room;
        this.params = params;
    }

    public void saveWithFetch(boolean useProxy) {
        synchronized (this) {
            try {
                total++;
                long a = System.currentTimeMillis();
                while (useProxy && App.PROXY_DATA_QUEUE.isEmpty()) {
                    Thread.sleep((long)1000);
                }

                String result = null;
                if(useProxy){
                    int reIndex = 0;
                    while (true){
                        if(reIndex >= CrawlerConfig.MAX_RETRY){
                            logger.error("Room ID [ " + this.room.getStr("id") + " ] NO RESOURCE ...");
                            int retry = room.getInt("retry_num") + reIndex;
                            room.set("retry_num", retry);
                            room.set("retry_date",CrawlerConfig.SIMPLE_DATETIME_FORMATTER.format(new Date()));
                            Db.use().update(room,new Entity("airbnb_room").set("id",this.room.getLong("id")));
                            return;
                        }
                        proxy = App.PROXY_THREAD_MAP.get(Thread.currentThread().getId());
                        if(proxy == null || proxy.getExpireTime().before(new Date())){
                            proxy = ProxyService.getProxyData();
                            logger.info("PROXY [" + proxy.getIp() + ":"  + proxy.getPort() + "    -   "  + CrawlerConfig.DATETIME_FORMATTER.format(proxy.getExpireTime()) + "] is Using ......");
                        }
                        try {
                            result = catcher.catchDocumentWithProxy(AirBnbConfig.SCHEDULE_URL, params, proxy).body();
                            //logger.info("-------------------  RETRY " + retry + " - " +reIndex);
                        }catch (Exception ex)
                        {
                            //ex.printStackTrace();
                            logger.error("--->  RETRY [ " + reIndex +" ] 获取数据失败!" + ex.getMessage());
                            Thread.sleep((long) 1000);

                        }
                        if( result != null){
                            break;
                        }
                        reIndex ++;
                    }

                    //logger.info(proxy.getIp() + ":" + proxy.getPort() + " 访问时间:" + (System.currentTimeMillis() - a) + "   访问结果: " + result);
                    logger.info(proxy.getIp() + ":" + proxy.getPort() + " 访问时间:" + (System.currentTimeMillis() - a) );
                }else{
                    result = catcher.catchDocument(AirBnbConfig.SCHEDULE_URL, params).body();
                    logger.info(" 访问时间:" + (System.currentTimeMillis() - a));
                    //logger.info(" 访问时间:" + (System.currentTimeMillis() - a) + "   访问结果: " + result);
                }

                JSONArray canlendarMonthsJson = JSONUtil.parseObj(result).getJSONArray("calendar_months");
                if (canlendarMonthsJson == null) {
                    logger.error("Room ID [ " + this.room.getStr("id") + " ] NO ACCESS ...");
                    Integer errorCode = JSONUtil.parseObj(result).getInt("error_code");
                    if (errorCode != null) {
                        try {
                            Db.use().del(new Entity("airbnb_room").set("id", this.room.getStr("id")));
                        } catch (SQLException ex) {
                            ex.printStackTrace();
                            logger.error(ex.getMessage());
                        }
                    }
                    return;
                }

                JSONArray canlendarJson = canlendarMonthsJson.getJSONObject(0).getJSONArray("days");

                for (int i = 0; i < canlendarJson.size(); i++) {
                    JSONObject obj = canlendarJson.getJSONObject(i);
                    String date = obj.getStr("date");

                    Date yesterday = DateTimeUtil.yesterday();
                    if (DateUtil.parse(date).after(yesterday)) {
                        Boolean available = obj.getBool("available");
                        Boolean availableForCheckin = obj.getBool("available_for_checkin");
                        JSONObject priceObj = obj.getJSONObject("price");

                        try {
                            String[] dateArray = date.split("-");
                            String tableName = "airbnb_room_booking_" + dateArray[0] + "_" + dateArray[1];
                            Entity whereEntity = Entity.create(tableName);
                            whereEntity.set("room_id", room.getStr("id"));
                            whereEntity.set("date", date);

                            Entity bookingEntity = Entity.create(tableName);
                            bookingEntity.set("room_id", room.getStr("id"));
                            bookingEntity.set("date", date);
                            bookingEntity.set("is_price_upon_request", priceObj.getStr("is_price_upon_request"));
                            bookingEntity.set("is_used", available);
                            bookingEntity.set("local_price_formatted", priceObj.getStr("local_price_formatted"));
                            bookingEntity.set("native_adjusted_price", priceObj.getBigDecimal("native_adjusted_price"));
                            bookingEntity.set("native_currency", priceObj.getStr("native_currency"));
                            bookingEntity.set("native_price", priceObj.getBigDecimal("native_price"));
                            bookingEntity.set("type", priceObj.getStr("type"));

                            DBUtil.save(bookingEntity,whereEntity);
                        } catch (SQLException e) {
                            logger.info("Save RoomID [ " + room.getStr("id") + " ] ERROR,Exception:" + e.getMessage());
                            e.printStackTrace();
                        }
                    }
                }
                success++;

            } catch (Exception e) {
                e.printStackTrace();
                //logger.error("获取数据失败!" + e.getMessage());
                failed ++;
            } finally {
                //logger.info("总次数/成功次数/失败次数："+ total +"/"+success + "/"+failed);
            }
        }
    }

}
